package com.yhc.common.util;

import cn.hutool.core.codec.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;


public class HMacUtil {

    private final static Logger log = LoggerFactory.getLogger(HMacUtil.class);

    private final static String ENCRY_HMACSHA256 = "HmacSHA256";

    public static void main(String[] args) {
        try {
            String str = "request={\"userId\":\"17603870338\",\"param\":{\"taskList\":[{\"taskConfigDetailId\":1681980536523390976,\"finishDateTime\":\"2023-07-20\"},{\"taskConfigDetailId\":1681988946988417024,\"finishDateTime\":\"2023-07-20\"}]}}&type=1";
            String key = "4e648716ac4846909496a8727f5fa84c";

            SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), ENCRY_HMACSHA256);
            Mac mac = Mac.getInstance(signingKey.getAlgorithm());
            mac.init(signingKey);
            mac.update(str.getBytes(StandardCharsets.UTF_8));
            byte[] s = mac.doFinal();
            String signed_str = byte2Base64(byte2hex(s));
            System.out.println(signed_str);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String encrypt(Map<String, Object> data, String key) {
        if (CollectionUtils.isEmpty(data)) {
            return null;
        }
        String signed_str;
        try {
            SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), ENCRY_HMACSHA256);
            Mac mac = Mac.getInstance(signingKey.getAlgorithm());
            mac.init(signingKey);
            mac.update(generateReqParams(data).getBytes(StandardCharsets.UTF_8));
            byte[] s = mac.doFinal();
            signed_str = byte2Base64(byte2hex(s));
            return signed_str;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String generateReqParams(Map<String, Object> data) {
        StringBuilder sb = new StringBuilder();
        List<String> strings = new ArrayList<String>();
        for (String key : data.keySet()) {
            if ("sign".equals(key)) {
                continue;
            }
            Object valO = data.get(key);
            String val = null;
            if (valO instanceof String) {
                val = (String) valO;
            } else {
                val = JacksonUtil.marshallToString(valO);
            }
            if (!StringUtils.isBlank(val) && !"null".equals(val)) {
                strings.add(key + "=" + val);
            }
        }
        Collections.sort(strings);
        for (int i = 0; i < strings.size(); i++) {
            if (i != strings.size() - 1) {
                sb.append(strings.get(i)).append("&");
            } else {
                sb.append(strings.get(i));
            }
        }
        String result = sb.toString();
        log.info("# sign param: {}", result);
        return result;
    }

    // 二进制转字符串
    private static String byte2hex(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b != null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1)
                hs.append('0');
            hs.append(stmp);
        }
        return hs.toString().toLowerCase();
    }

    private static String byte2Base64(String str) {
        return Base64.encode(str.getBytes());
    }
}
